#!/usr/bin/python2.4


import cStringIO

import utils


class Tag(object):

  __slots__ = 'name', 'contents', 'attrs'

  def __init__(self, name, *args, **dargs):
    self.name = name
    if args:
      self.contents = list(args)
    else:
      self.contents = None
    if dargs:
      self.attrs = dargs
    else:
      self.attrs = None

  def get_contents(self):
    if self.contents is None:
      return []
    else:
      return self.contents

  def set_contents(self, op):
    if self.contents is None:
      contents = []
      op(contents)
      if contents:
        self.contents = contents
    else:
      op(self.contents)

  def get_attrs(self):
    if self.attrs is None:
      return {}
    else:
      return self.attrs

  def set_attrs(self, op):
    if self.attrs is None:
      attrs = {}
      op(attrs)
      if attrs:
        self.attrs = attrs
    else:
      op(self.attrs)

  def __call__(self, *args, **dargs):
    if self.contents is None and self.attrs is None:
      instance = self
    else:
      instance = Tag(self.name, *self.get_contents(), **self.get_attrs())
    instance.update(*args, **dargs)
    return instance

  def __delitem__(self, key):
    if isinstance(key, (int, long, slice)):
      del self.get_contents()[key]
    else:
      del self.get_attrs()[key]

  def __getitem__(self, key):
    if isinstance(key, (int, long, slice)):
      return self.get_contents()[key]
    else:
      return self.get_attrs()[key]

  def __setitem__(self, key, value):

    def setitem(data):
      data[key] = value

    if isinstance(key, (int, long, slice)):
      self.set_contents(setitem)
    else:
      self.set_attrs(setitem)

  def update(self, *args, **dargs):

    def extend(contents):
      contents.extend(args)

    def update(attrs):
      utils.update_dict(attrs, dargs)

    if args:
      self.set_contents(extend)
    if dargs:
      self.set_attrs(update)

  def __iadd__(self, other):
    self.update(other)
    return self

  def render(self, write, indent=0):
    contents = self.get_contents()
    attrs = self.get_attrs()

    if indent is None:
      single = True
    else:
      single = attrs.get('_s')

    if single:
      next_indent = None
      sep = attrs.get('_sep')
    else:
      next_indent = indent + 1
      sep = '\n%s' % ('\t' * next_indent)

    write('<%s' % self.name)
    for k, v in attrs.iteritems():
      if k.startswith('_'):
        continue
      if k.endswith('_'):
        k = k[:-1]
      write(' %s="%s"' % (k, v))

    write('>')
    for i, item in enumerate(contents):
      if not single or (i and sep):
        write(sep)
      if isinstance(item, Tag):
        item.render(write, next_indent)
      else:
        write(str(item))

    if not attrs.get('_nc'):
      if not single:
        write('\n%s' % ('\t' * indent))
      write('</%s>' % self.name)

  def render_html(self, write):
    write('<!DOCTYPE html>\n')
    self.render(write, 0)

  def render_to_str(self, indent=0):
   s = cStringIO.StringIO()
   if indent:
     s.write('\t' * indent)
   self.render(s.write, indent)
   return s.getvalue()

  def __str__(self):
    return self.render_to_str()


class TagCreator(object):

  def __getattr__(self, name):
    if name.startswith('_'):
      raise AttributeError('%r object has no attribue %r' %
                           (type(self).__name__, name))
    return Tag(name)


tag = TagCreator()
